/**
 * build_project
 * <p>
 * Copyright 2014 cayden.cn, Inc. All rights reserved.
 *
 * @author Administrator
 * @date 2021-06-21 13:42
 */
package com.cayden.config.project.componets.db;

import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 *
 * @author cayden
 * @date 2021-06-21 13:42
 */
@ConfigurationProperties(prefix = DruidProperties.PREFIX)
@Setter
@Getter
@Slf4j
public class DruidProperties implements BeanClassLoaderAware {

    public static final String PREFIX = "cayden.ds";

    public static final String ENABLE_KEY = PREFIX + ".enable";

    public static final int DEFAULT_SLOW_SQL_THRESHOLD = 1000;

    /**
     * 默认最大连接数
     */
    private static final int MYSQL_MAX_ACTIVE = 300;

    private String prefix = PREFIX;

    /**
     * 是否启用此组件
     */
    private boolean enable = true;

    /**
     * jdbc url
     */
    private String url;

    private String username;

    private String password;

    /**
     * 初始连接数
     */
    private Integer initialSize = 5;

    /**
     * 最小连接数
     */
    private Integer minIdle = 20;

    /**
     * 最大连接数
     */
    private Integer maxActive = 300;


    /**
     * 获取连接等待超时的时间
     */
    private Integer maxWait = 10000;

    private ClassLoader beanClassLoader;

    /**
     * 编译初始化mysql链接参数
     * @return
     */
    public DruidDataSource build(){
        this.chick();
        if (this.beanClassLoader == null){
            this.beanClassLoader = ClassUtils.getDefaultClassLoader();
        }

        DruidDataSource dataSource = new DruidDataSource();

        // 设置基础信息
        dataSource.setDriverClassLoader(this.getBeanClassLoader());
        dataSource.setUrl(this.fetchUrl());
        dataSource.setUsername(this.getUsername());
        dataSource.setPassword(this.getPassword());
        //应用程序可以自定义的参数
        dataSource.setInitialSize(this.getInitialSize());
        dataSource.setMinIdle(this.getMinIdle());
        if (mysql()){
            maxActive = Math.max(maxActive, MYSQL_MAX_ACTIVE);
            System.setProperty("spring.jpa.database", "MYSQL");

            // 设置支持utf8mb4
            dataSource.setConnectionInitSqls(Lists.newArrayList("set names utf8mb4;"));
        }

        dataSource.setMaxActive(maxActive);
        dataSource.setMaxWait(this.getMaxWait());
        //检测需要关闭的空闲连接间隔，单位是毫秒
        dataSource.setTimeBetweenEvictionRunsMillis(300000);
        //连接在池中最小生存的时间
        dataSource.setMinEvictableIdleTimeMillis(3600000);
        dataSource.setTestWhileIdle(true);
        //从连接池中获取连接时不测试
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
        dataSource.setValidationQueryTimeout(5);
        dataSource.setRemoveAbandoned(true);
        dataSource.setRemoveAbandonedTimeout(3600);
        dataSource.setLogAbandoned(true);
        if (this.mysql()) {
            String validationQuery = "select 'x'";
            dataSource.setValidationQuery(validationQuery);
            dataSource.setValidationQueryTimeout(2);
        }
        return dataSource;
    }

    private boolean mysql() {
        return isMysql(this.url);
    }

    private String fetchUrl() {
        return normalizeUrl(this.url);
    }

    private String normalizeUrl(String url) {
        if (isMysql(url) && !url.contains("?")) {
            return url
                    + "?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false";
        }
        return url;
    }

    public static boolean isMysql(String url) {
        return url.toLowerCase().startsWith("jdbc:mysql");
    }

    private void chick() {
        // todo 检查当前初始化参数是否完整，如果不完整，需要采取默认配置
        if (enable) {
            Assert.hasText(url, "数据库连接" + PREFIX + ".url不能为空");
            Assert.hasText(username, "数据库用户名" + PREFIX + ".username不能为空");
            Assert.hasText(password, "数据库密码" + PREFIX + ".password不能为空");
        }
    }


    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.beanClassLoader = classLoader;
    }
}
